package com.societyGames.codeAlong.state.codeExercise.view
{
import com.societyGames.codeAlong.state.codeExercise.model.Exception;
import com.societyGames.codeAlong.state.codeExercise.model.ExceptionEvent;
import com.societyGames.codeAlong.state.codeExercise.model.StackTraceCallMessage;
import com.societyGames.codeAlong.state.codeExercise.model.StackTraceMessage;
import com.societyGames.codeAlong.state.codeExercise.model.SyntaxErrorMessage;
import com.societyGames.codeAlong.state.codeExercise.model.SyntaxErrorMessageEvent;
import com.societyGames.flashForms.DynamicTextField;
import com.societyGames.flashForms.basicSkin.SharedTextFields;
import com.societyGames.system.EventObject;
import com.societyGames.utility.HyperTextEscape;

import flash.events.TextEvent;
import flash.system.Capabilities;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

public class OutputTextField extends DynamicTextField
{
  //Exceptions
  private var _exceptionStackCallClickedEventObject:EventObject; //StackTraceCallEvent
  private var _helpExceptionClickedEventObject:EventObject;  //ExceptionEvent
  private var _exception:Exception;
  private var _linkableFileName:String; //The file name that should hotlink.

  //Syntax Errors
  private var _syntaxErrorClickedEventObject:EventObject;  //SyntaxErrorMessageEvent
  private var _helpSyntaxErrorClickedEventObject:EventObject;  //SyntaxErrorMessageEvent
  private var _syntaxErrorMessage:SyntaxErrorMessage;

  //General
  private var _escapeTextField:TextField = new TextField();

  private static const FONT_BEGIN_TAG:String = "<FONT FACE=\"Inconsolata\" SIZE=\"" + SharedTextFields.TEXT_LARGE_SIZE + "\" COLOR=\"#000000\" LETTERSPACING=\"0\" KERNING=\"0\">";
  private static const FONT_END_TAG:String = "</FONT>";

  public function OutputTextField()
  {
    //Exceptions
    this._exceptionStackCallClickedEventObject = new EventObject(this, "EXCEPTION_STACK_CALL_CLICKED");
    this._helpExceptionClickedEventObject = new EventObject(this, "HELP_EXCEPTION_CLICKED");

    //Syntax Error
    this._syntaxErrorClickedEventObject = new EventObject(this, "SYNTAX_ERROR_CLICKED");
    this._helpSyntaxErrorClickedEventObject = new EventObject(this, "HELP_SYNTAX_ERROR_CLICKED");

    //General
    var textFormat:TextFormat = new TextFormat();
    textFormat.font = "Inconsolata";
    textFormat.size = 16;
    this._escapeTextField.defaultTextFormat = textFormat;

    SharedTextFields.addStyle(this, SharedTextFields.FONT_STYLE);
    SharedTextFields.addStyle(this, SharedTextFields.LINK_STYLE);
    this.addEventListener(TextEvent.LINK, linkHandler);

    SharedTextFields.setDefaultRender(this);

    autoSize = TextFieldAutoSize.LEFT;
    multiline = true;

    /*background = true;
    backgroundColor = 0xFFFFFF;*/
  }

  //Exceptions
  public function get exceptionStackCallClickedEventObject():EventObject //StackTraceCallEvent
  {
    return this._exceptionStackCallClickedEventObject;
  }

  public function get helpExceptionClickedEventObject():EventObject //ExceptionEvent
  {
    return this._helpExceptionClickedEventObject;
  }

  public function set linkableFileName(value:String):void
  {
    this._linkableFileName = value;
  }

  public function set exception(value:Exception):void
  {
    this._exception = value;
    if (value != null) //null is clearing the exception
    {
      var htmlText:String = "";
      if (Capabilities.isDebugger)
      {
        var stackTraceMessage:StackTraceMessage = this._exception.stackTraceMessage;
        htmlText += stackTraceMessage.messageToString() + "\n";
        for (var index:int = 0; index < stackTraceMessage.calls.length; index++)
        {
          var stackTraceCallMessage:StackTraceCallMessage = stackTraceMessage.calls[index];
          if (stackTraceCallMessage.sourceFile == this._linkableFileName && stackTraceCallMessage.lineNumber >= 0)
          {
            htmlText += stackTraceCallMessage.atWithTabs + " " + stackTraceCallMessage.functionName + "[<a href=\"event:stack:" + index.toString() + "\">" + stackTraceCallMessage.sourceFile + ":" +
                    (stackTraceCallMessage.lineNumber + 1).toString() + "</a>]<br>";
          }
          else
          {
            htmlText += stackTraceCallMessage.toString() + "<br>";
          }
        }
        htmlText += "<br><a href=\"event:helpException\">Help</a>";
      }
      else //If we don't have a stack trace message, just print out the normal exception text.
      {
        htmlText += this._exception.error.toString() + "\n";
        htmlText += "<br><a href=\"event:helpException\">Help</a><br><br>";
        htmlText += "<b>Make debugging exceptions much easier:</b><br>";
        htmlText += "<b><a href=\"http://www.adobe.com/support/flashplayer/downloads.html\" target=\"_blank\">Install</a> the Flash Debug Player.</b><br><br>";
        htmlText += "The debug player will display:<br>";
        htmlText += "<li>Line numbers</li>";
        htmlText += "<li>Exception messages</li>";
        htmlText += "<li>Call stack</li>";
      }
      this.htmlText += FONT_BEGIN_TAG + htmlText + FONT_END_TAG;
    }
    else
    {
      this.htmlText += "";
    }
  }

  public function showUnknownException():void
  {
    this.htmlText += "Unknown exception. Add a try-catch block to your main code."
  }
  //<--Exceptions

  //Syntax Error-->
  public function get syntaxErrorClickedEventObject():EventObject //SyntaxErrorMessageEvent
  {
    return this._syntaxErrorClickedEventObject;
  }

  public function get helpSyntaxErrorClickedEventObject():EventObject  //SyntaxErrorMessageEvent
  {
    return this._helpSyntaxErrorClickedEventObject;
  }

  public function set syntaxErrorMessage(value:SyntaxErrorMessage):void
  {
    this._syntaxErrorMessage = value;
    if (value != null)
    {
      this.htmlText += FONT_BEGIN_TAG + "<a href=\"event:syntaxError\">Line: " + (this._syntaxErrorMessage.line + 1).toString() + "</a>" + HyperTextEscape.escape(this._syntaxErrorMessage.message) + "<br><br><a href=\"event:helpSyntaxError\">Help</a>" + FONT_END_TAG;
    }
    else
    {
      this.htmlText += "";
    }
  }
  //<--Syntax Error

  private function linkHandler(event:TextEvent):void
  {
    if (event.text == "helpException")
    {
      this._helpExceptionClickedEventObject.dispatchEvent(new ExceptionEvent(this._helpExceptionClickedEventObject.type, this._exception));
    }
    else if (event.text.indexOf("stack:") == 0)
    {
      var indexText:String = event.text.substr("stack:".length);
      var index:int = int(indexText);
      this._exceptionStackCallClickedEventObject.dispatchEvent(new StackTraceCallEvent(this._exceptionStackCallClickedEventObject.type, this._exception.stackTraceMessage.calls[index]));
    }
    else if (event.text == "syntaxError")
    {
      this._syntaxErrorClickedEventObject.dispatchEvent(new SyntaxErrorMessageEvent(this._syntaxErrorClickedEventObject.type, this._syntaxErrorMessage));
    }
    else if (event.text == "helpSyntaxError")
    {
      this._helpSyntaxErrorClickedEventObject.dispatchEvent(new SyntaxErrorMessageEvent(this._helpSyntaxErrorClickedEventObject.type, this._syntaxErrorMessage));
    }
  }

  override public function appendText(text:String):void
  {
    htmlText += htmlEscape(text);
  }

  private function htmlEscape(text:String):String
  {
    this._escapeTextField.text = text;
    return this._escapeTextField.htmlText;
  }
}
}